package interfaces.clients.connection;

import exceptions.FatalDebugException;
import exceptions.FatalException;
import exceptions.Util;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Vector;

/**
 * A class implementing clients' port listener.<br>
 * <br>
 *
 * @author Mihail A. Muhin
 */
//TODO: interruption after errors
public class PortListener extends Thread {
	//port to listen to
	//TODO: read it from settings object
	private final static int port = 5000;

	//how long to wait for child threads
	//TODO: read it from settings object
	private final static int close_request_timeout = 10000;

	//how often does the thread checks close_request
	//TODO: read it from settings object
	private final static int accept_timeout = 500;

	//was close commands sent by main server thread or not
	private boolean close_request = false;

	/**
	 * Tells listener thread that it should finish.<br>
	 * <br>
	 * <p/>
	 * When told, thread will wait for all clients' commands to complete and then close itself.
	 */
	public void Close() {
		close_request = true;
	}

	private void internal_run() {
		ServerSocket ss = null;
		Vector handlers = new Vector(100, 100);

		try {
			ss = new ServerSocket(port);
		} catch (IOException e) {
			throw new FatalException(
					"Couldn't create ServerSocket. Maybe port ".concat((new Integer(port)).toString()).concat(
							" is already listened"));
		}

		try {
			ss.setSoTimeout(accept_timeout);
		} catch (SocketException e) {
			try {
				ss.close();
			} catch (IOException e1) {
				throw new FatalDebugException("Couldn't close opened ServerSocket", e1);
			}
			throw new FatalException("setSoTimeout failed. Error in underlying protocol");
		}

		while (!close_request) {
			try {
				Thread.sleep(1000);
				Socket cs = ss.accept();
				Handler h = new Handler(cs);
				h.start();
				handlers.add(h);
			} catch (SocketTimeoutException e) {
				//just a way to make iterations of "while" regular
			} catch (IOException e) {
				Util.LogError("Error while waiting for the user connection");
			} catch (InterruptedException e) {
				Util.LogError("No InterruptedException should occure while the client's listener process is sleeping");
			}
		}

		int i;
		for (i = 0; i < handlers.size(); i++) {
			Handler h = (Handler) handlers.get(i);
			try {
				h.join(close_request_timeout);
			} catch (InterruptedException e) {
				Util.LogError("No InterruptedException should occure while the client's listener process is sleeping");
			}
		}
	}

	public void run() {
		try {
			internal_run();
		} catch (FatalException e) {
			Util.ShowFatalError(e.getMessage());
		} catch (FatalDebugException e) {
			Util.ShowFatalError(e.getMessage());
//    } catch (CorrectableException e){
//      Util.LogError(e.getMessage());
//    } catch (CorrectableDebugException e){
//      Util.LogError(e.getMessage());
		} catch (RuntimeException e) {
			Util.ShowFatalError(e.getMessage());
		}
	}
}
